package com.project.common.screens;

import interfaces.IAppManager;

import java.io.IOException;
import java.net.ServerSocket;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

import service.IMService;
import type.TaskDescriptions;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.PixelFormat;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.text.InputFilter;
import android.text.method.PasswordTransformationMethod;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.project.institute.DAO.Institute;
import com.project.trac.R;

import core.modules.DatabaseConnector;

public class Login extends Institute implements OnClickListener, TaskDescriptions {

	private EditText et_username;
	private EditText et_password;
	private EditText et_dialog_input;

	private Dialog dialog;
	private AlertDialog.Builder alertDialog_Builder;
	private ProgressDialog progressDialog;

	private TextView tv_message;
	private TextView tv_register;
	private TextView tv_dialog_spiel;
	private View layout;
	private CheckBox showPassword;
	private Button btn_login;

	// String required for login
	private String et_USERNAME;
	private String et_PASSWORD;
	private String INPUT_CODE;
	int ctr = 0;

	private String IDENTIFIER;
	private String command = "command";
	    
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.commons_login);
		setTitle("Welcome to TRAC!");
		
        /*
         * Start and bind the  imService 
         **/
    	startService(new Intent(Login.this,  IMService.class));	
		
		showPassword = (CheckBox) findViewById(R.id.showpassword);
		btn_login = (Button) findViewById(R.id.btn_login);
		tv_register = (TextView) findViewById(R.id.tv_register);
		et_username = (EditText) findViewById(R.id.et_username);
		et_password = (EditText) findViewById(R.id.et_password);
		
		btn_login.setOnClickListener(this);
		tv_register.setOnClickListener(this);
		showPassword.setOnClickListener(this);
		
		// Custom Dialog Layout
		layout = View.inflate(getApplicationContext(), R.layout.generic_dialog_box, null);
		et_dialog_input = (EditText) layout.findViewById(R.id.et_dialog_input);
		tv_dialog_spiel = (TextView) layout.findViewById(R.id.tv_dialog_spiel);
		
		et_dialog_input.setFilters(new InputFilter[] {  new InputFilter.LengthFilter(6) });
		
		progressDialog = new ProgressDialog(Login.this);
		alertDialog_Builder = new AlertDialog.Builder(Login.this);
		tv_message = new TextView(this);

		/* build custom dialog box */
		alertDialog_Builder.setTitle("Information").setIcon(android.R.drawable.ic_dialog_info);
		alertDialog_Builder.setCancelable(true);
		
		tv_dialog_spiel.setText("For faculty members,\nan authorization code is required.");
		tv_message.setTextAppearance(this, R.style.alert_message);
		tv_message.setGravity(Gravity.CENTER_HORIZONTAL);

		// Pre-check for connectivity
//		if (!isNetworkConnected()) {
//			msg.setText("Please check Wifi hardware availability");
//			alertDialog.setView(msg)
//			.setCancelable(false)
//			.setPositiveButton(android.R.string.ok,
//					new DialogInterface.OnClickListener() {
//				public void onClick(DialogInterface dialog,int id) {
//					Login.this.finish();
//				}
//			}).create().show();
//		} else if (!isWifiAvailable() && !isNetworkConnected()) {
//		msg.setText("An internet connection is required to login!");
//		alertDialog.setView(msg)
//		.setPositiveButton(android.R.string.ok,
//				new DialogInterface.OnClickListener() {
//			// TODO invoke fix wifi setting
//			public void onClick(DialogInterface dialog, int id) {
//				dialog.dismiss();
//			}
//		}).create().show();
//			
//		} else if (isWifiAvailable() && isNetworkConnected()) {
			new AsynchronousTask().execute(VALIDATE);
//		}


	}

	@Override
	public void onSaveInstanceState(Bundle outState) {
		outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
		super.onSaveInstanceState(outState);
	}
	
	@Override
	public void onClick(View v) {
		
		switch (v.getId()) {
		
			case R.id.btn_login:
				
				et_USERNAME =  et_username.getText().toString();
				et_PASSWORD = et_password.getText().toString();

				List<EditText> e = new ArrayList<EditText>();
				e.add(et_password);
				e.add(et_username);

				for (EditText et : e) {
					if (et.getText().toString().length() == 0) {
						et.setError("required");
					}
				}

				try {
					String success = new AsynchronousTask().execute(LOGIN).get();
					command = LOGIN;
					
					if (success.equalsIgnoreCase("success")) {
						getFriendsList();
					} else {
						Toast.makeText(getApplicationContext(), "login failed!", Toast.LENGTH_LONG).show();
					}
					
				} catch (InterruptedException e2) {
					DatabaseConnector.Logger(getClass(), "AsynchronousTask - Login", e2);
				} catch (ExecutionException e2) {
					DatabaseConnector.Logger(getClass(), "AsynchronousTask - Login", e2);
				} catch (NullPointerException e2) {
					DatabaseConnector.Logger(getClass(), "AsynchronousTask - Login", e2);
				}
				
				break;
				
			case R.id.showpassword:
				
				if (showPassword.isChecked()) {
					et_password.setTransformationMethod(null);
				} else {
					et_password.setTransformationMethod(new PasswordTransformationMethod());
				}
				
				break;
				
			case R.id.tv_register:
				
				/** - - - - - New User - - - - -  */
				alertDialog_Builder.setPositiveButton("I'm a teacher!", new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						INPUT_CODE = et_dialog_input.getText().toString();
						if (IDENTIFIER.equals(INPUT_CODE)) {
							et_dialog_input.setText("");
							setRole(0);
							dialog.cancel();
							startActivity(new Intent(Login.this, Registration.class));
							((ViewGroup) layout.getParent()).removeView(layout);
						} else {
							Toast.makeText(getBaseContext(), "Invalid faculty code.", Toast.LENGTH_LONG).show();
							et_dialog_input.setText("");
							ctr++;
							if (ctr == 3) {
								tv_message.setText("Invalid faculty code for 3 times, \n system shutdown");
								alertDialog_Builder.setTitle("Alert!");
								alertDialog_Builder.setIcon(android.R.drawable.ic_dialog_alert);
								alertDialog_Builder.setView(tv_message);
								alertDialog_Builder.setNegativeButton(android.R.string.ok,new DialogInterface.OnClickListener() {
									@Override
									public void onClick(DialogInterface arg0, int arg1) {
										et_dialog_input.setText("");
										finish();
										((ViewGroup) layout.getParent()).removeView(layout);
									}
								});

							}
						} //end if-else
					}
				});
				
				alertDialog_Builder.setNegativeButton("I'm a student!", new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						INPUT_CODE = et_dialog_input.getText().toString();
						if (INPUT_CODE.isEmpty()) {
							startActivity(new Intent(Login.this, Registration.class));
							setRole(1);
						} else {
							Toast.makeText(getBaseContext(), "No need for a faculty code.", Toast.LENGTH_LONG).show();
							et_dialog_input.setText("");
							dialog.cancel();
							((ViewGroup) layout.getParent()).removeView(layout);
						}
					}
				});
				
				dialog = alertDialog_Builder.setTitle("New Registration").setView(layout).create();
				dialog.show();
				
				break;
		}
	}
	
	@Override
	public void onAttachedToWindow() {
		super.onAttachedToWindow();
		Window window = getWindow();
		window.setFormat(PixelFormat.RGBA_8888);
	}
	
	@Override
	protected void onPause() {
		unbindService(mConnection);
		super.onPause();
	}

	@Override
	protected void onResume() {		
		bindService(new Intent(Login.this, IMService.class), mConnection , Context.BIND_AUTO_CREATE);
		super.onResume();
	}
	
	private long lastPress;
	@Override
	public void onBackPressed() {

		long currentTime = System.currentTimeMillis();
		if (currentTime - lastPress > 3500) {
			Toast.makeText(getBaseContext(), "Press back again to exit.", Toast.LENGTH_LONG).show();
			lastPress = currentTime;
		} else {
			finish();
		}
	}
	
	private class AsynchronousTask extends AsyncTask<String, String, String> {
		
		ResultSet rs;

		protected void onPreExecute() {
			super.onPreExecute();
			if (command.equalsIgnoreCase(LOGIN)) {
				progressDialog.setMessage("logging in...");
			} else {
				progressDialog.setMessage("please wait...");
			}

			progressDialog.setIcon(android.R.drawable.ic_dialog_info);
			progressDialog.setIndeterminate(true);
			progressDialog.setCancelable(true);
			progressDialog.show();

		}

		protected String doInBackground(String... args) {

			try {

				if (args[0].equalsIgnoreCase(VALIDATE)) {
					rs = DatabaseConnector.getStatement().executeQuery("SELECT * FROM code");
					while (rs.next()) {
						IDENTIFIER = rs.getString("identifier");
					}
				} 
				
				if (args[0].equalsIgnoreCase(LOGIN)) {
					
					rs = DatabaseConnector.getStatement().executeQuery
							("SELECT id, FirstName, username, password, isstudent FROM users WHERE username = '" 
							 + et_USERNAME + "' AND password = '" + et_PASSWORD + "'");

					while (rs.next()) {
						
						if (et_USERNAME.equalsIgnoreCase(rs.getString("username")) 
								&& et_PASSWORD.equalsIgnoreCase(rs.getString("password"))) {
								setRole(rs.getInt("isStudent"));
								setUsername(rs.getString("username"));
								setPassword(rs.getString("password"));
								setFirstName(rs.getString("FirstName"));
								setUserID(rs.getInt("id"));

								ServerSocket s = new ServerSocket(0);
								
							    DatabaseConnector.getConnection().setAutoCommit(false);
								DatabaseConnector.setPreparedStatement(
										"UPDATE users SET IP= \"" + DatabaseConnector.getLocalIPAddress() + "\", PORT=" + s.getLocalPort() + " WHERE id = " + getUserID() + ";");
								PreparedStatement set = DatabaseConnector.getPreparedStatement();
								set.executeUpdate();
									
								set.close();
						    	return "success";
						}
					}
				}
			} catch (SQLException e) {
				DatabaseConnector.Logger(getClass(), "doInBackground", e);
			} catch (IOException e) {
				DatabaseConnector.Logger(getClass(), "doInBackground", e);
			}

			return "fail";
		}

		protected void onPostExecute(String postExecute) {
			if (progressDialog.isShowing()) {
				progressDialog.dismiss();
			}

		}
	}
	
	// ============================================================= IM Service

	public static final String AUTHENTICATION_FAILED = "0";
	public static final String FRIEND_LIST = "FRIEND_LIST";

	private IAppManager imService;
	String result;

	private ServiceConnection mConnection = new ServiceConnection() {
		public void onServiceConnected(ComponentName className, IBinder service) {
			// This is called when the connection with the service has been
			// established, giving us the service object we can use to
			// interact with the service. Because we have bound to a explicit
			// service that we know is running in our own process, we can
			// cast its IBinder to a concrete class and directly access it.
			imService = ((IMService.IMBinder) service).getService();

			if (imService.isUserAuthenticated() == true) {
				System.out.println("imService.isAuthenticated");
			} else {
				System.out.println("!imService.isAuthenticated");
			}
		}

		public void onServiceDisconnected(ComponentName className) {
			// This is called when the connection with the service has been
			// unexpectedly disconnected -- that is, its process crashed.
			// Because it is running in our same process, we should never
			// see this happen.
			imService = null;
			Toast.makeText(Login.this, "IMService Stopped.", Toast.LENGTH_SHORT).show();
		}
	};
	
	public void getFriendsList() {
		
		if (imService == null) {
			// showDialog(NOT_CONNECTED_TO_SERVICE);
			Toast.makeText(Login.this, "Service unavailable.", Toast.LENGTH_SHORT).show();
		} else if (imService.isNetworkConnected() == false) {
			// showDialog(NOT_CONNECTED_TO_NETWORK);
			Toast.makeText(Login.this, "Network not found.", Toast.LENGTH_SHORT).show();
		}
		
		
		Thread loginThread = new Thread() {
			private Handler handler = new Handler();

			@Override
			public void run() {
				result = imService.authenticateUser(getUsername(), getPassword());
				if (result == null || result.equals(AUTHENTICATION_FAILED)) {
					/*
					 * Authentication failed, inform the user
					 */
					handler.post(new Runnable() {
						public void run() {
							Toast.makeText(Login.this, "IM authentication failed", Toast.LENGTH_SHORT).show();
							Log.e("AUTHENTICATION FAILED", "Authentication failed: " + getUsername() + " , " + getPassword());
						}
					});

				} else {

					/*
					 * if result not equal to authentication failed, result
					 * is equal to friend list of the user
					 */
					
					handler.post(new Runnable() {
						public void run() {
							startActivity(new Intent(Login.this, Dashboard.class));
						}
					});

				} // end else
			}
		};
		loginThread.start();

	}

}